﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IceDog.DNL.CSharp.Grammar.ThreadAndAsync
{
    /// <summary>
    /// https://www.cnblogs.com/neverc/p/4653539.html
    /// </summary>
    /// <remarks>
    /// 线程测试需要在IceDog.DNL.CSharp.Command进行测试，单元测试不支持多线程和异步
    /// 另外在末尾需要一句Console.ReadLine();来保证主线程没有退出，不然无显示结果
    /// </remarks>
    public class ThreadTestManager
    {
        #region ThreadTest1
        private void ThreadTest()
        {
            var name = Thread.CurrentThread.Name;
            var id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine($"Thread name {name},id {id} 休眠 1000ms");
            Thread.Sleep(1000);
            Console.WriteLine($"Thread name {name},id {id} 休眠结束");
        }
        /// <summary>
        /// 
        /// </summary>
        public void TestMethod1()
        {
            //.Net 在1.0的时候，就已经提供最基本的API.
            new Thread(ThreadTest)
            {
                IsBackground = false,
                Name = "BaseThread"
            }.Start();
            //线程池中取空闲线程执行委托（方法）
            ThreadPool.QueueUserWorkItem(o => ThreadTest());
            //.Net 4.0以上可用
            Task.Run(() => ThreadTest());
            Thread.CurrentThread.Name = "MainThread";
            var name = Thread.CurrentThread.Name;
            var id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine($"Main Thread, name {name},id {id}");
            Console.ReadLine();
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>

        public void TestMethod2()
        {
            Task.Run(() =>                                          //异步开始执行
            {
                Thread.Sleep(1000);                                 //异步执行一些任务
                Console.WriteLine("Task Thread");                   //异步执行完成标记
            });
            Thread.Sleep(1100);                                     //主线程在执行一些任务
            Console.WriteLine("Main Thread");                       //主线程完成标记
            Console.ReadLine();
        }

        #region ThreadTest3
        private static async void MainThread()
        {
            var thread = TaskThread();
            Thread.Sleep(1100);                                     //主线程在执行一些任务
            Console.WriteLine("Main Thread");                       //主线程完成标记
            Console.WriteLine(await thread);                        //await 主线程等待取异步返回结果
        }

        private static async Task<string> TaskThread()
        {
            return await Task.Run(() =>
            {
                Thread.Sleep(1000);                                 //异步执行一些任务
                return "Task Thread";                               //异步执行完成标记
            });
        }

        /// <summary>
        /// Main函数不能使用async标记
        /// </summary>

        public void TestMethod3()
        {
            MainThread();
            Console.ReadLine();
        }
        #endregion

        #region TestMethod4
        public static bool IsComplete { get; set; }

        public static void ThreadDelegate()
        {
            Console.WriteLine($"IsComplete:{IsComplete}");
            if (!IsComplete)
            {
                Thread.Sleep(500);
                Console.WriteLine("执行完成");
                IsComplete = true;
            }
        }
        /// <summary>
        /// 线程不安全，会出现两个执行完成
        /// </summary>

        public void TestMethod4()
        {
            Task.Run(() => ThreadDelegate());
            Task.Run(() => ThreadDelegate());
            Console.ReadLine();
        }
        #endregion

        #region TestMethod5
        private static readonly object lockObj = new object();
        public static void ThreadDelegateLock()
        {
            Console.WriteLine($"IsComplete:{IsComplete}");
            lock (lockObj)
            {
                if (!IsComplete)
                {
                    Thread.Sleep(500);
                    Console.WriteLine("执行完成");
                    IsComplete = true;
                }
            }
        }
        /// <summary>
        /// 线程安全，会出现一个执行完成
        /// 线程锁的技术使一块代码只能一个线程进入。
        /// </summary>

        public void TestMethod5()
        {
            Task.Run(() => ThreadDelegateLock());
            Task.Run(() => ThreadDelegateLock());
            Console.ReadLine();
        }
        #endregion

        #region TestMethod6
        //信号量
        private static readonly SemaphoreSlim Slim = new SemaphoreSlim(2);
        private static async void ThreadDelegateSemaphoreSlim(object i)
        {
            Console.WriteLine("准备执行" + i);
            await Slim.WaitAsync();
            Console.WriteLine("开始执行" + i);
            //todo other
            await Task.Delay(1000);
            Console.WriteLine("执行结束" + i);
            Slim.Release();
        }
        /// <summary>
        /// 信号量（SemaphoreSlim）例子
        /// 信号量的存在，则是让同一块代码指定多个线程进入。
        /// 多个线程分别调用同一个方法进行处理问题
        /// </summary>
        public void TestMethod6()
        {
            for (int i = 0; i < 5; i++)
            {
                ThreadPool.QueueUserWorkItem(ThreadDelegateSemaphoreSlim, i);
            }
            Console.ReadLine();
        }
        #endregion

        #region TestMethod7
        /// <summary>
        /// 此方法缺少await，将以同步的方式运行
        /// </summary>
        /// <returns></returns>
        private async Task<int> CalculateAsync()
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"calculating step {i + 1}");
            }
            Random random = new Random();
            return random.Next();
        }
        /// <summary>
        /// https://blog.csdn.net/daguanjia11/article/details/52488847
        /// </summary>
        public async void TestMethod7()
        {
            Console.WriteLine("before call CalculateAsync");
            Task<int> calculateResult = CalculateAsync();
            Console.WriteLine("after call CalculateAsync");
            int result = await calculateResult;
            Console.WriteLine($"result is {result}");
            Console.ReadLine();
        }
        #endregion

        #region TestMethod8
        private async void T8MyAsyncMethod()
        {
            Console.WriteLine("call T8CalculateAsync.....");
            Task<int> calculateResult = T8CalculateAsync();
            Console.WriteLine("call T8CalculateAsync complete.......");
            int result = await calculateResult;
            Console.WriteLine($"result is {result}");
        }

        private async Task<int> T8CalculateAsync()
        {
            Console.WriteLine("T8Calculate begin.....");
            int t = await Task.Run(() => T8Calculate());
            Console.WriteLine("T8Calculate complete.....");
            return t;
        }

        private int T8Calculate()
        {
            // Compute total count of digits in strings.
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                Console.WriteLine($"calculating step {i + 1}");
            }
            Random random = new Random();
            return random.Next();
        }


        /// <summary>
        /// 
        /// </summary>
        public void TestMethod8()
        {
            Console.WriteLine("you can enter some text while other task is running。");
            T8MyAsyncMethod();
            string input;
            while ((input = Console.ReadLine()) != "q")
            {
                Console.WriteLine($"your input is {input}");
            }
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        public void TestMethodX()
        {

        }
    }
}
